#include<iostream>
#include<unistd.h>
#include<pthread.h>//原生线程库的头文件
#include<sys/types.h>
#include<unistd.h>
#include<stdlib.h>
#include<vector>
const int threadnum = 5;
//-----------------1. 验证多线程的创建----------------------
//-----------------2. 验证线程传参可以传递基本信息，也可以传递其他对象(包括自定义的)-----------------------
class Task
{
    public:
    Task()
    {}
    ~Task()
    {
    }
    void SetData(int x,int y)
    {
        datax = x;
        datay = y;
    }
    int Excute()
    {
        return datax+datay;
    }
    private:
    int datax;
    int datay;
};
class ThreadData:public Task
{
    public:
        ThreadData(int x,int y,const std::string& threadname):_threadname(threadname)
        {
            _t.SetData(x,y);
        }
        std::string threadname()
        {
            return _threadname;
        }
        int run()
        {
            return _t.Excute();
        }

    private:
        std::string _threadname;
        Task _t;
};


class Result
{
    public:
    Result()
    {}
    ~Result()
    {}
    void SetResult(int result,const std::string threadname)
    {
        _result = result;
        _threadname = threadname;
    }
    void Print()
    {
        std::cout<<_threadname<<" : "<<_result<<std::endl;
    }

    private:
        int _result;
        std::string _threadname;
};
void * handlerTask(void * args)
{
    //std::string threadname  = static_cast<char*>(args);
    // const char* threadname = static_cast<char*>(args);
    // while(true)
    // {
    //     sleep(2);
    //     std::cout<<"  I am "<<threadname <<std::endl;
    // }
    // delete[] threadname;
    ThreadData*td = static_cast<ThreadData*>(args);
    std::string name = td->threadname();//获取线程名字
    Result *res = new Result();
    int result = td->run();//获取线程运行结果
    res->SetResult(result,name);
    delete td;
    sleep(2);

    return res;
}
int main()
{
    std::vector<pthread_t> thread;
    for(int i = 0;i < threadnum;i++)
    {
        //char threadname[64];每一个线程都指向同一块空间，会覆盖前面前面线程所写内容。
        char* threadname = new char[64];//每个线程都指向不同的堆上空间，
        snprintf(threadname,64,"thread-%d",i+1);
        pthread_t tid;
        ThreadData*td = new ThreadData(10,20,threadname);//在堆上开辟
        pthread_create(&tid,nullptr,handlerTask,td);
        thread.push_back(tid);
    }
    std::vector<Result*>result_set;
    void* ret = nullptr;

    //回收线程
    for(auto& tid : thread)
    {
        pthread_join(tid,&ret);
        result_set.push_back((Result*)ret);
    }
    //输出结果
    for(auto& res : result_set)
    {
        res->Print();
        delete res;
    }
    return 0;
}





















//-------------同一个进程内的线程，大部分资源都是共享的，地址空间是共享的---------
int g_val = 100;
std::string ToHex(pthread_t tid)
{
    char id[64];
    snprintf(id,sizeof(id),"0x%lx",tid);
    return id;
}
  //-------------线程退出问题--------------------------
    //1. 代码跑完，结果对
    //2. 代码跑完，结果错
    //3. 出异常------多线程中，任何一个线程出现异常，都会导致整个进程退出！
void* newthreadrun(void * args)
{
    int cnt = 5;
    while(cnt--)
    {
        std::string name = (char*)args;
        printf("new thread ,g_val:%d ,&g_val:%p\n",g_val,&g_val);
        //pthread_self()函数和getpid()类似获取线程id
        //std::cout<<name <<" am new thread,pid: "<<getpid()<<"new thread id::" << ToHex(pthread_self())<<std::endl;
        // g_val++;
        // int *p = nullptr;
        // *p = 100;//野指针异常
        sleep(1);
    }
    std::cout<<"new thread quit ..."<<std::endl;
    int *ret = (int*)malloc(sizeof(int));
    *ret = 42; // 假设这是线程的返回值
    //exit(10);不能用exit()来终止线程，他是终止进程的
    //pthread_exit((void*)120);
    return (void*)120;
}
//------------线程退出问题-----------------
//主线程退出 == 进程退出 == 所有线程都要退出
//1. 往往我们需要将main thread 最后退出
//2. 线程也需要被“wait”，否则会出现类似于进程没有被等待的问题---资源泄露问题。---通过pthread_join()函数回收子线程
//3. pthread_exit()退出线程
//4. pthread_cancel()在确保线程已经启动，下终止线程。---向线程发送撤销请求
int main()
{
    //---------------线程id问题--------------------------
    pthread_t tid;
    void *thread_ret;

    //---------------创建线程----------------------------
    pthread_create(&tid,nullptr,newthreadrun,(void*)"thread-1");
    //1. &tid:指向一个pthread_t类型的变量，该变量用于接收新创建线程的ID
    //2. nullptr:指向一个pthread_attr_t 类型的变量，该变量用于设置新线程的属性。如果传递nullptr，则新线程的属性为默认属性
    //3. newthreadrun:这是一个函数指针，指向新线程将要执行的函数，该函数的返回类型为void*
    //4. (void*)"thread-1": 这是一个指针，指向新·线程传递参数，如果不需要传参，可以传递nullptr。


    //--------------线程回收问题-------------------------
    //1. pthread_join()函数只能用于等待已经终止的线程，如果尝试对未终止的线程进行等待，调用线程会阻塞至目标线程终止，
    //2. tid：要等待的线程的id，nullptr：是一个指针，指向线程的返回值。
    //3. 成功返回0，错误时，返回一个错误号
    //4. 我们为什么没有像进程一样获取线程退出的退出信号？只有你手动写的退出码？---一旦线程出现异常信号，整个进程就会退出，没有机会获取退出信号
    //5. 不考虑线程异常情况
    sleep(2);
    pthread_cancel(tid);



    // sleep(5);
    // while(true)
    // {
    //     // std::cout<<"I am main thread,pid:" <<getpid()<<"new thread id: "<<ToHex(tid)<<
    //     // "main thread id: "<<ToHex(pthread_self())<<std::endl;
    //     printf("mian thread ,g_val:%d ,&g_val:%p\n",g_val,&g_val);
    //     sleep(1);
    // }
    int n = pthread_join(tid,&thread_ret);
    std::cout<<"mian thread quit, n = "<<n<<std::endl;
    std::cout<<"--------------------------"<<std::endl;
    //PTHREAD_CANCELED;(void*)-1
    std::cout<<"main thread get ret = "<<(long long )thread_ret<<std::endl;
    //--------------新线程和老线程，谁先运行？-------------
    //不确定，由调度器决定
    return 0;
}